package com.example.demo.jeePay;

import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.JeepayClient;
import com.jeequan.jeepay.exception.JeepayException;
import com.jeequan.jeepay.model.PayOrderCreateReqModel;
import com.jeequan.jeepay.model.RefundOrderCreateReqModel;
import com.jeequan.jeepay.request.PayOrderCreateRequest;
import com.jeequan.jeepay.request.RefundOrderCreateRequest;
import com.jeequan.jeepay.response.PayOrderCreateResponse;
import com.jeequan.jeepay.response.RefundOrderCreateResponse;
import org.springframework.stereotype.Component;

import jakarta.annotation.Resource;
import java.util.Map;

/**
 * JeePay支付工具类
 * 提供支付和退款功能的封装，简化JeePay SDK的使用
 * 
 * @author MingChang.Wei
 * @since 2025/6/3
 */
@Component
public class JeePayUtil {
    private static final Log log = LogFactory.get();

    @Resource
    private JeePayConfig jeePayConfig;

    /**
     * 创建支付订单
     * 
     * @param params 支付参数，包含以下字段：
     *               <ul>
     *               <li>orderNo - 商户订单号（必填）</li>
     *               <li>wayCode - 支付方式，默认QR_CASHIER（聚合扫码）</li>
     *               <li>amount - 支付金额，单位分（必填）</li>
     *               <li>clientIp - 客户端IP地址（必填）</li>
     *               <li>subject - 商品名称（必填）</li>
     *               <li>body - 商品描述（可选）</li>
     *               <li>notifyUrl - 异步通知地址（可选）</li>
     *               <li>returnUrl - 同步跳转地址（可选）</li>
     *               </ul>
     * @return 支付结果数据，包含支付二维码等信息；失败时返回null
     * @throws JeepayException 支付接口调用异常
     */
    public JSONObject jeePay(Map<String, Object> params) throws JeepayException {
        log.info("~~~~~~~~~~~~~~~~~~~开始进行支付操作~~~~~~~~~~~~~~~~~~~");

        if (StrUtil.isEmpty((String) params.get("wayCode"))) {
            params.put("wayCode", "QR_CASHIER");
        }

        JeepayClient client = JeepayClient.getInstance(jeePayConfig.getAppId(), jeePayConfig.getApiKey(), jeePayConfig.getApiBase());
        PayOrderCreateRequest request = new PayOrderCreateRequest();
        PayOrderCreateReqModel model = getPayOrderCreateReqModel(client, params);
        request.setBizModel(model);

        PayOrderCreateResponse response = client.execute(request);
        if (response.isSuccess(jeePayConfig.getApiKey())) {
            return response.getData();
        } else {
            log.error("支付失败：{}", response.getMsg());
        }
        log.info("~~~~~~~~~~~~~~~~~~~支付操作完成~~~~~~~~~~~~~~~~~~~");
        return null;
    }

    /**
     * 创建退款订单
     * 
     * @param params 退款参数，包含以下字段：
     *               <ul>
     *               <li>orderNo - 商户订单号（与payOrderId二选一）</li>
     *               <li>payOrderId - 支付订单号（与orderNo二选一）</li>
     *               <li>mchRefundNo - 商户退款单号（必填）</li>
     *               <li>amount - 退款金额，单位分（必填）</li>
     *               <li>clientIp - 客户端IP地址（必填）</li>
     *               <li>reason - 退款原因（可选）</li>
     *               <li>notifyUrl - 异步通知地址（可选）</li>
     *               </ul>
     * @return 退款结果数据；失败时返回null
     * @throws JeepayException 退款接口调用异常
     */
    public JSONObject jeeRefund(Map<String, Object> params) throws JeepayException {
        log.info("~~~~~~~~~~~~~~~~~~~开始进行退款操作~~~~~~~~~~~~~~~~~~~");
        JeepayClient client = JeepayClient.getInstance(jeePayConfig.getAppId(), jeePayConfig.getApiKey(), jeePayConfig.getApiBase());
        RefundOrderCreateRequest request = new RefundOrderCreateRequest();
        RefundOrderCreateReqModel model = getRefundOrderCreateReqModel(client, params);
        request.setBizModel(model);

        RefundOrderCreateResponse response = client.execute(request);
        // 判断退款发起是否成功（并不代表退款成功）退款状态 0-订单生成 1-退款中 2-退款成功 3-退款失败 4-退款关闭
        if (response.isSuccess(jeePayConfig.getApiKey()) && response.get().getState() == 2) {
            return response.getData();
        } else {
            log.error("退款失败：{}", response.getMsg());
        }
        log.info("~~~~~~~~~~~~~~~~~~~退款操作完成~~~~~~~~~~~~~~~~~~~");
        return null;
    }

    /**
     * 构建支付订单请求模型
     * 
     * @param client JeePay客户端实例
     * @param params 支付参数
     * @return 支付订单请求模型
     */
    private PayOrderCreateReqModel getPayOrderCreateReqModel(JeepayClient client, Map<String, Object> params) {
        PayOrderCreateReqModel model = new PayOrderCreateReqModel();
        model.setMchNo(jeePayConfig.getMchNo());
        model.setAppId(client.getAppId());
        model.setMchOrderNo((String) params.get("orderNo"));
        model.setWayCode((String) params.get("wayCode"));
        model.setAmount((Long) params.get("amount"));
        model.setCurrency("CNY");
        model.setClientIp((String) params.get("clientIp"));
        model.setSubject((String) params.get("subject"));
        model.setBody((String) params.get("body"));
        model.setNotifyUrl((String) params.get("notifyUrl"));
        model.setReturnUrl((String) params.get("returnUrl"));
        model.setChannelExtra(channelExtra());
        model.setExtParam("");

        return model;
    }

    /**
     * 构建渠道扩展参数
     * 设置支付数据类型为二维码图片URL
     * 
     * @return 渠道扩展参数JSON字符串
     */
    private String channelExtra() {
        JSONObject obj = new JSONObject();
        obj.put("payDataType", "codeImgUrl");
        return obj.toJSONString();
    }

    /**
     * 构建退款订单请求模型
     * 
     * @param client JeePay客户端实例
     * @param params 退款参数
     * @return 退款订单请求模型
     */
    private RefundOrderCreateReqModel getRefundOrderCreateReqModel(JeepayClient client, Map<String, Object> params) {
        RefundOrderCreateReqModel model = new RefundOrderCreateReqModel();
        model.setMchNo(jeePayConfig.getMchNo());
        model.setAppId(client.getAppId());
        model.setMchOrderNo((String) params.get("orderNo"));
        model.setPayOrderId((String) params.get("payOrderId"));
        model.setMchRefundNo((String) params.get("mchRefundNo"));
        model.setRefundAmount((Long) params.get("amount"));
        model.setCurrency("CNY");
        model.setClientIp((String) params.get("clientIp"));
        model.setRefundReason((String) params.get("reason"));
        model.setNotifyUrl((String) params.get("notifyUrl"));
        model.setChannelExtra("");
        model.setExtParam("");
        return model;
    }
}
